/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : protocol.c
 * Author        : joki.zhu
 * Date          : 2019-10-10
 *
 * Record        :
 * 1.Date        : 2019-10-10
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/
#include "protocol.h"
#include "app_common.h"
#include "MediaPack.h"
#include "DevKey.h"
#include "DevSocSub.h"
#include "DevWifi.h"
#include "System.h"
#include "Audio.h"
#include "Video.h"
#include "UpgradeRecovery.h"
#include "NtpClient.h"

#ifdef ZDK_PROTOCOL
#include "RealTime_apiv1.h"
#endif

#ifdef FACTOOL_PROTOCOL
#include "FacTool.h"
#endif

#ifdef ALEXA_PROTOCOL
#include "Alexa_webrtc.h"
 #endif

#ifdef YD_PROTOCOL
#include "DOTSdkAPI.h"
#include "DOTHejiaguhua.h"
#include "DOTSdkMedia.h"
#include "Net.h"
#include "voipenginec_api.h"
#include "DevConfig.h"
#endif

#ifdef MOBILE_DM
#include "MobileCountry/dm/DmManager.h"
#endif

typedef struct tagSendInfo{
 	char flagDoorBell;         //doorbell flag
	char flagDoorBell_zdk;     //zdk sned doorbell ok flag
	char flagDoorBell_alexa;   //alexa send doorbell ok flag
	char flagPickAlarm;        //pickalarm flag

	int  timeDoorBell;
	int  timePickAlarm;
}EventSendInfo;

typedef struct {
    char bInited;
    unsigned int ydProtocolPid;
    EventSendInfo stEventSendInfo;
}protocol_context_s;

 static protocol_context_s g_protocolCtx = {
    .bInited                    = 0,
    .ydProtocolPid              = 0,
    .stEventSendInfo            = {0},
 };

 static inline protocol_context_s *protocol_get_ctx(void)
 {
     return &g_protocolCtx;
 }

 #ifdef YD_PROTOCOL
 
 static char g_YDProtocol_outIp[32] = "";

 void *DOTYDProtocolThread(void*args)
 {
	 SET_THREAD_NAME("DOTYDProtocolThread");
	 pthread_detach(pthread_self());
	 
	 time_t start_time = time(NULL);
	 static time_t curTime = 0;
	 
	 while (1)
	 {	 
		 NetLiteosGetAddrInfo("www.baidu.com", g_YDProtocol_outIp);
		 if (strlen(g_YDProtocol_outIp) > 0)
			 break;

		 usleep(50* 1000);
	 }
 
	 pthread_exit(0);
 }


void *YDProtocolInit(void *args)
{
	 int iRet = 0;
	 //说明：
	 //此修改是为了规避上电起来程序挂掉，固话先初始化后再初始SDK 
	 //程序挂几率变小
	 int count = 0;
	protocol_context_s *ctx = protocol_get_ctx();

	SYSTEM_WAKEUP_TYPE_E WakeUpType = SYS_WAKEUP_TYPE_BUFF;
	SocSubGetWakeUpType(&WakeUpType);
	if (WakeUpType == SYS_WAKEUP_TYPE_KEY_BELL)
		DOTGetAwakeType(1);
	else if (WakeUpType == SYS_WAKEUP_TYPE_KEY_PICK)
		DOTGetAwakeType(2);
	else if (WakeUpType == SYS_WAKEUP_TYPE_PIR)
		DOTGetAwakeType(3);

	pthread_t DotYDProtocolPid;
	int err = pthread_create(&DotYDProtocolPid, NULL, &DOTYDProtocolThread, NULL);
	if (err != 0) {
		LOGE("pthread_create MobileCountryThread failed!\n");
		return -1;
	}
#if 1
	 while (1)
	 {
	 	 if (GetConfigWifiQrcodeStatus())
		 {
			 DotSdkInit();
			 DOTStartBind(4);
		 }

		 if (strlen(g_YDProtocol_outIp) > 0)
		 {
			 LOGD("=========YDProtocolInit===========\n");		 
			 DotSdkInit();
			 DOTHejiaguhuaInit();
			 break;
		 }
		 usleep(50 * 1000);
	 }
#else
	 DotSdkInit();
#endif
	 
	iRet = LOS_TaskDelete(ctx->ydProtocolPid);
	 if (0 != iRet) {
		 LOGE("%s[%d]:delete task fail[%d]",__func__,__LINE__,iRet);
	 }
	ctx->ydProtocolPid = 0;

}

#endif

void *tskProtocolInit(void*args)
{
	int ret = 0;
    SET_THREAD_NAME("tskProtocolInit");
    pthread_detach(pthread_self());  

	protocol_context_s *ctx = protocol_get_ctx();
	
#ifdef ZDK_PROTOCOL
    UpgradeRecoverySelfCheck();
    
    char   type = DevType_FamilyBell;   
    RealTimeInit(type);
#endif

#ifdef YD_PROTOCOL
	 unsigned int		 ul_ret;
	 int				 l_ret;
	 unsigned char		 uc_status;
	 TSK_INIT_PARAM_S	 st_hsl_task;

	 memset(&st_hsl_task, 0, sizeof(TSK_INIT_PARAM_S));
	 st_hsl_task.pfnTaskEntry = (TSK_ENTRY_FUNC)YDProtocolInit;
	
	 //st_hsl_task.uwStackSize	= LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
	 st_hsl_task.uwStackSize  = 0x8000;
	 st_hsl_task.pcName 	  = "YDProtocolInit";
	 st_hsl_task.usTaskPrio   = 10;
	 st_hsl_task.uwResved	  = LOS_TASK_STATUS_DETACHED;
	 ul_ret = LOS_TaskCreate(&ctx->ydProtocolPid, &st_hsl_task);
	 if(0 != ul_ret){
		LOGE("%s[%d]:create task fail[%d]",__func__,__LINE__,ul_ret);
		return -1;
	 }
#endif

#ifdef MOBILE_DM
		start_dm();
#endif

#if defined(FACTOOL_PROTOCOL) && !defined(SYSTEM_SAFE_MODE)
	FacTool_Init();
#endif

#ifdef ALEXA_PROTOCOL
	LOGE("Alexaid===>>>>>>>>>>>>>>\n");
	char strAlexaid[32] = {0};
	char strUid[20] = {0};
	
    if (DevConfigGetAlexaid(strAlexaid, sizeof(strAlexaid)) < 0 || 
        DevConfigGetUuid(strUid, sizeof(strUid)) < 0) 
    {
        LOGE("DevGetAlexaId or DevGetUuid uid fail\n");
        return NULL;
    }
    LOGI("Alexaid=%s strUid=%s\n",strAlexaid, strUid);
    if(0 != Alexa_Start(strAlexaid, strUid)){  
        LOGE("Alexa_Start fail\n");
    }
#endif

    ctx->bInited = 1;
    
    pthread_exit(0);
    return NULL;
}

static int protocol_check_ntp_is_success()
{
	time_t          t 	= 0;
	struct tm       tmTime = {0};	

	t 	= time(NULL);
	gmtime_r(&t, &tmTime);

	if(tmTime.tm_year + 1900 > 2018){
		LOGD("ntp success [%d]\n", tmTime.tm_year + 1900);
		return 0;
	}
	LOGE("ntp fail [%d]\n", tmTime.tm_year + 1900);
	return -1;
}

static int protocol_push_low_power_msg(BATTERY_STATUS_S *pstBatStatus)
{
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(!UpgradeCheckIsRun(), -1, "upgrade is running");
    
	int nret = 0;
#ifdef ZDK_PROTOCOL
	RT_BAT_Status batInfo;
	memset(&batInfo, 0, sizeof(batInfo));
	batInfo.capacity       = pstBatStatus->capacity;
	batInfo.chargingStatus = pstBatStatus->chargingStatus;
	batInfo.isLowBatState  = pstBatStatus->isLowBatState;
	nret = RealTimeUploadLowBatAlarm(batInfo);
	LOGI("RealTimeUploadLowBatAlarm nret=%d capacity=%d\n", nret , batInfo.capacity);
#endif

#ifdef YD_PROTOCOL
	LOGE("YD_PROTOCOL_low_power event--->>>>\n");
	MC_EVENT_ATTR_S stEventAttr;
	memset(&stEventAttr, 0, sizeof(stEventAttr));
	stEventAttr.bLowBatteryEvent = 1;
	stEventAttr.LowBatteryEvent_capacity = pstBatStatus->capacity;
	DOTSetEventState(&stEventAttr);

#endif /* YD_PROTOCOL */

	return nret;  //not low pwer
}

int protocol_push_pir_msg()
{
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(!UpgradeCheckIsRun(), -1, "upgrade is running");

	int nret = 0;
	int  bPirStat  = 0;

    nret = DevConfigGetPirSwitch(&bPirStat);
	if(0 == nret){
		LOGI("DevConfigGetPirSwitch =%d\n", bPirStat);
		if(1 == bPirStat){  //md
		
#ifdef ZDK_PROTOCOL
        if(0 == WifiCheckIsConnected()){
            return -1;
        }
        RealTimeSetPutAlarmSwitch();
#endif

#ifdef YD_PROTOCOL
        LOGE("YD_PROTOCOL_CheckPir--->>>>\n");
	MC_EVENT_ATTR_S stEventAttr;
	memset(&stEventAttr, 0, sizeof(stEventAttr));
	stEventAttr.bPIREvent = 1;
	stEventAttr.PIREvent_utcms = get_utc_ms();
	DOTSetEventState(&stEventAttr);
#endif /* YD_PROTOCOL */

		}else if(2 == bPirStat){//stay

		}else if(3 == bPirStat){//long time stay

		}else{//0

		}
	}

#ifdef ALEXA_PROTOCOL
	static char FlagAlexa = 0;
	if(0 == FlagAlexa){
		nret = Alexa_DoorbellPri();
		if(0 == nret){
			FlagAlexa = 1;
		}
	}
#endif
	return nret;
}

static int protocol_push_door_bell_msg(void)
{
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(!UpgradeCheckIsRun(), -1, "upgrade is running");
    
	int nretZdk   = 0;
	int nretAlexa = 0;
	protocol_context_s *ctx = protocol_get_ctx();
	
#ifdef ALEXA_PROTOCOL
	if(0 == ctx->stEventSendInfo.flagDoorBell_alexa){
		nretAlexa = Alexa_DoorbellPress();
		if(0 != nretAlexa){
			LOGE("Alexa_DoorbellPress fail err=%d\n", nretAlexa);
		}else{
			LOGD("Alexa_DoorbellPress ok\n");
			ctx->stEventSendInfo.flagDoorBell_alexa = 1;
		}
	}
#endif
	
#ifdef ZDK_PROTOCOL
	RT_LockMsgInfo lockinfo;

	if(0 == ctx->stEventSendInfo.flagDoorBell_zdk){
		memset(&lockinfo, 0, sizeof(lockinfo));
		lockinfo.MsgType = RT_LOCK_DOORBELL;
		if(0 == ctx->stEventSendInfo.timeDoorBell){
			lockinfo.TimeStamp = time(NULL);
		}else{
			lockinfo.TimeStamp = ctx->stEventSendInfo.timeDoorBell;
		}
		nretZdk = RealTimeUploadLockMsgInfo(lockinfo);
		if(0 != nretZdk){
			LOGE("zdk send DoorBell fail\n");
		}else{
			LOGD("zdk send DoorBell ok\n");
			ctx->stEventSendInfo.flagDoorBell_zdk = 1;
		}
	}
#endif

#ifdef YD_PROTOCOL
	static char g_has_awake = 0;
	LOGE("YD_PROTOCOL_DoorBell sent event--->>>>\n");
	MC_EVENT_ATTR_S stEventAttr;
	memset(&stEventAttr, 0, sizeof(stEventAttr));
	stEventAttr.bBellEvent = 1;
	stEventAttr.BellEvent_utcms = get_utc_ms();
	DOTSetEventState(&stEventAttr);

	SYSTEM_WAKEUP_TYPE_E WakeUpType = SYS_WAKEUP_TYPE_BUFF;
	SocSubGetWakeUpType(&WakeUpType);

	if (g_has_awake == 0)
	{
		g_has_awake++;
		if (WakeUpType == SYS_WAKEUP_TYPE_KEY_BELL)
			nretZdk = DOTHjghPressDoorbell(1);
		else
			nretZdk = DOTHjghPressDoorbell(0);
		}
	else
	{
		DOTHjghPressDoorbell(0);
	}

#endif /* YD_PROTOCOL */

	if(0 != nretZdk || 0 != nretAlexa){
		return -1;
	}
	return 0;
}

static int protocol_push_pick_alarm_msg(void)
{
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(!UpgradeCheckIsRun(), -1, "upgrade is running");

	int nret = 0;
    protocol_context_s *ctx = protocol_get_ctx();
	
#ifdef ZDK_PROTOCOL
	RT_LockMsgInfo lockinfo;
	memset(&lockinfo, 0, sizeof(lockinfo));
	lockinfo.MsgType = RT_LOCK_PICKALARM;
	if(0 == ctx->stEventSendInfo.timePickAlarm){
		lockinfo.TimeStamp = time(NULL);
	}else{
		lockinfo.TimeStamp = ctx->stEventSendInfo.timePickAlarm;
	}
	nret = RealTimeUploadLockMsgInfo(lockinfo);
#endif

#ifdef YD_PROTOCOL
	LOGE("YD_PROTOCOL_PickAlarm--->>>>\n");
	PowerSetSocSleepTime(1, 20);
	MC_EVENT_ATTR_S stEventAttr;
	memset(&stEventAttr, 0, sizeof(stEventAttr));
	stEventAttr.bAlarmEvent = 1;
	//stEventAttr.bLowBatteryEvent = 1;
	stEventAttr.AlarmEvent_utcms = get_utc_ms();
	DOTSetEventState(&stEventAttr);

#endif /* YD_PROTOCOL */


	return nret;
}

int OnDoorBellEvent(void)
{
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(!UpgradeCheckIsRun(), -1, "upgrade is running");

	int  nret = -1;
	protocol_context_s *ctx = protocol_get_ctx();
	
	LOGE("doorbell--->>>>\n");

	ctx->stEventSendInfo.flagDoorBell_zdk = 0;  
	ctx->stEventSendInfo.flagDoorBell_alexa = 0; 
	if(0 == WifiCheckIsConnected()){
		ctx->stEventSendInfo.flagDoorBell = 1;
		if(0 == protocol_check_ntp_is_success()){ //ntp ok
			ctx->stEventSendInfo.timeDoorBell = time(NULL);
		}
		LOGE("network is error,send DoorBell fail\n");
		return -1;
	}
	nret = protocol_push_door_bell_msg();
	if(0 != nret){
		ctx->stEventSendInfo.flagDoorBell = 1;  
		if(0 == protocol_check_ntp_is_success()){ //ntp ok
			ctx->stEventSendInfo.timeDoorBell = time(NULL);
		}
	}else{
		ctx->stEventSendInfo.flagDoorBell = 0; 
		LOGD("regist send doorbell ok\n");
	}
	return nret;
}

int OnPickAlarmEvent(void)
{
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(!UpgradeCheckIsRun(), -1, "upgrade is running");

    char alarmSwitch = -1;
    protocol_context_s *ctx = protocol_get_ctx();
    
    DevConfigGetAlarmSwitch(&alarmSwitch);
    if (alarmSwitch == 0) {
        LOGW("pick alarm switch is off!!!\n");
        return -1;
    }

    while ( AudioGetOpsHandle()->play_file_start(AUDIO_ALARM, AUDIO_TYPE_MP3, 0) < 0) {
        usleep(50 * 1000);
    }
    
	int  nret = -1;
	LOGE("pickalarm--->>>>\n");
	if(0 == WifiCheckIsConnected()){
		ctx->stEventSendInfo.flagPickAlarm = 1;
		if(0 == protocol_check_ntp_is_success()){ //ntp ok
			ctx->stEventSendInfo.timePickAlarm = time(NULL);
		}
		LOGE("network is error,send PickAlarm fail\n");
		return -1;
	}
	nret = protocol_push_pick_alarm_msg();
	if(0 != nret){
		ctx->stEventSendInfo.flagPickAlarm = 1; 
		if(0 == protocol_check_ntp_is_success()){ //ntp ok
			ctx->stEventSendInfo.timePickAlarm = time(NULL);
		}
	}else{
		ctx->stEventSendInfo.flagPickAlarm = 0; 
		LOGD("regist send pickalarm ok\n");
	}
	return nret;
}

static int restore_factory_default_cb(void)
{
	LOGW("Restorre factory default!!!\n");
	
	UpgradeRecoverySetState(0);
	UpgradeRecoverySetRetryCnt(0);
	
	return 0;
}

static int system_enter_ultra_deepsleep_cb(void)
{
    int ret = 0;
    
    LOGW("system enter ultra deepsleep...\n");

    while ( AudioGetOpsHandle()->play_file_start(AUDIO_POWER_OFF, AUDIO_TYPE_MP3, 0) < 0) {
        usleep(50 * 1000);
    }

    while ( AudioGetOpsHandle()->play_file_start("", AUDIO_TYPE_MP3, 0) < 0) {
        usleep(50 * 1000);
    }
    
    SocSubSetResetSwitch(0);
    ret = SocSubSetSystemMode(HI_SYSLINK_SYS_MODE_ULTRA_DEEPSLEEP);
    if (ret != 0) {
        LOGE("SocSubSetSystemMode failed\n");
        SocSubSetSystemMode(1);
    }

    return 0;
}

void *tskRunTimeNtp(void *args)
{
    SET_THREAD_NAME("tskRunTimeNtp");
    pthread_detach(pthread_self());

    int ret = 0;
	SYSTEM_TIME stTime;

    while (1) 
    {
        if (1 == WifiCheckIsConnected())
        {
            ret = NtpClientSyncTime();
            if (ret < 0) {
                LOGW("NtpClientSyncTime failed\n");
                usleep(50 * 1000);
                continue;
            }
            /* sync time to mcu */
            memset(&stTime, 0, sizeof(stTime));
            SystemGetCurrentTimeUtc(&stTime);
            SocSubSetTime(stTime);
            LOGI(">>>>>>>> ntp client sync time ok!\n");
            break;
        }
        else
        {
            usleep(100 * 1000);
        }
    }
    
    pthread_exit(0);
}

static int protocol_run_ntp(void)
{
    int ret = 0;
    pthread_t startTimeNtpPid;
    
    ret = pthread_create(&startTimeNtpPid, NULL, &tskRunTimeNtp, NULL);
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, -1, "pthread_create tskRunTimeNtp");
    
    return 0;
}

static int protocol_check_wakeup_event(void)
{
    static char eventFlag = 0; /* 0:没有获取到 1:已获取但没发送 2:已获取且发送成功 */
	static SYSTEM_WAKEUP_TYPE_E WakeUpType = SYS_WAKEUP_TYPE_BUFF;
    protocol_context_s *ctx = protocol_get_ctx();

    if (eventFlag == 0)  /* 没有获取到唤醒事件类型 */
    {
        if(0 == SocSubGetWakeUpType(&WakeUpType)){
            eventFlag = 1;
            LOGD("SocSubGetWakeUpType is %d\n", WakeUpType);
        }
    }

    if (eventFlag == 1) /* 已获取到唤醒事件类型,但还没有发送 */
    {
        switch(WakeUpType)
        {
            case SYS_WAKEUP_TYPE_PIR:           /**< PIR唤醒 */
                LOGD(">>> pir\n");
                if(0 == protocol_push_pir_msg()){
                    eventFlag = 2;
                }
                break;
            case SYS_WAKEUP_TYPE_KEY_BELL:      /**< 门铃按键唤醒 */
                OnDoorBellEvent();
                eventFlag = 2;
                break;
            case SYS_WAKEUP_TYPE_KEY_PICK:   /**< 防撬报警按键唤醒 */
                OnPickAlarmEvent();
                eventFlag = 2;
                break;
            case SYS_WAKEUP_TYPE_KEY_NETCFG:    /**< 网络配网按键唤醒 */                    
            case SYS_WAEKUP_TYPE_ALARM:         /**< 定时唤醒，处理完立刻休眠 */
            case SYS_WAKEUP_TYPE_WIFI:          /**< wifi远程唤醒 */
            case SYS_WAKEUP_TYPE_LOW_POWER:           /**< 电池低电唤醒 */
            case SYS_WAKEUP_TYPE_WDT:           /**< 看门狗唤醒 */
            case SYS_WAKEUP_TYPE_USB_CHARGE:    /**< USB充电唤醒 */
            case SYS_WAKEUP_TYPE_RECOVERY_WIFI: /**< 恢复wifi唤醒,处理完立刻休眠 */
                LOGD("SocSubGetWakeUpType wakeuptype=%d\n", WakeUpType);
                eventFlag = 2;
                break;
            default:
                break;
        }
    }

    /* DoorBell 检测没有发送成功再次发送 */
    if(1 == ctx->stEventSendInfo.flagDoorBell){
        if(0 == protocol_push_door_bell_msg()){
            LOGD("send doorbell ok\n");
            ctx->stEventSendInfo.flagDoorBell = 0;
            usleep(100*1000);
        }else{
            LOGE("send doorbell fail\n");
        }
    }
    
    /* Pickalarm 检测没有发送成功再次发送 */
    if(1 == ctx->stEventSendInfo.flagPickAlarm){
        if(0 == protocol_push_pick_alarm_msg()){
            LOGD("send pickalarm ok\n");
            ctx->stEventSendInfo.flagPickAlarm = 0;
            usleep(100*1000);
        }else{
            //LOGE("send pickalarm fail\n");
        }
    }

    return 0;
}

static int protocol_check_low_power(void)
{
    int ret = 0;
    static char sendFlag = 0; /* 0:没有获取到 1:已获取但没发送 2:已获取且发送成功 */
    static time_t start_time = 0;
	BATTERY_STATUS_S stBatStatus;
    
    if (sendFlag == 0) /* 没有获取到低电 */
    {
        time_t now_time = time(NULL);
        if (now_time >= start_time + 5) { /* 5s检测一次低电状态 */
            if(0 != SocSubGetBatteryStatus(&stBatStatus)){
                LOGE("SocSubGetBatteryStatus fail\n");
                return -1;
            }

            if (stBatStatus.isLowBatState) {
                LOGW("battery power is low !!!\n");
                sendFlag = 1;
            }
            start_time = time(NULL);
        }
    }

	if (sendFlag == 1) /* 获取到低电,准备发送 */
	{
        ret = protocol_push_low_power_msg(&stBatStatus);
        if(0 == ret){
            LOGD("send low power ok\n");
            sendFlag = 2; /* 实现只发送一次低电事件 */
        }else{
            LOGE("send low power fail\n");
        }
	}

	return 0;
}


void *tskCheckStatus(void *args)
{	
    SET_THREAD_NAME("tskCheckStatus");
    pthread_detach(pthread_self());
    
	protocol_context_s *ctx = protocol_get_ctx();

    /* start time ntp */
    protocol_run_ntp();

    while (1)
    {
//		if(0 == WifiCheckIsConnected() || 0 == ctx->bInited){
        if(0 == ctx->bInited){
			usleep(100*1000);
			continue;
		}

        /* check wakeup event */
        protocol_check_wakeup_event();

        /* check low power */
        protocol_check_low_power();

#ifdef ALEXA_PROTOCOL
		//check alexa session
		if(Alexa_Session_count() > 0){
			LOGD("Alexa set sleep time\n");
			PowerSetSocSleepTime(AV_TRUE, 6);
		}
#endif		
		usleep(500*1000);
    }

    pthread_exit(0);
	return NULL;
}

static int OnVideoData(int chn, MEDIA_PACK_VIDEO stPackVideo)
{
#ifdef ZDK_PROTOCOL
    char isIFrame = 0;
    isIFrame = stPackVideo.stDataType.enFrameType == MEDIA_VIDEO_FRAME_TYPE_I ? 1 : 0;
    RealTimeSendVideoData(0,isIFrame, stPackVideo.pFrameData, stPackVideo.frameSize, (unsigned int)(stPackVideo.timestamp/1000));
#endif /* ZDK_PROTOCOL */


#ifdef YD_PROTOCOL		
	int sync1 = 0;
	sync1 = stPackVideo.stDataType.enFrameType == MEDIA_VIDEO_FRAME_TYPE_I ? 1 : 0;
#if 0
	char addr[64] = "/sdcard/play.pcm";
	sprintf(addr, "/sdcard/video/%llu.h264", time(NULL));
	static FILE *fp = NULL;
	if (fp == NULL) {
		fp = fopen(addr, "wb");
		if (fp == NULL) {
			printf("fopen failed\n");
		}
	}

	if (1) {
		fwrite((unsigned char *)stPackVideo.pFrameData, 1, (unsigned int)stPackVideo.frameSize, fp);
		sync();
	}
#endif
	DOTVideoPushData(sync1, (unsigned char *)stPackVideo.pFrameData, (unsigned int)stPackVideo.frameSize,
									(unsigned int)(stPackVideo.timestamp/1000));
	if (DOTHjghCalling())
	{
		DOTHjghSendVideoOut(sync1, (unsigned char *)stPackVideo.pFrameData,
						(unsigned int)stPackVideo.frameSize);
	}
#endif /* YD_PROTOCOL */


#ifdef FACTOOL_PROTOCOL
    VIDEO_STREAM_ATTR_S streamAttr;
    
    memset(&streamAttr, 0, sizeof(streamAttr));
    if (VideoGetOpsHandle()->get_resolution(0, &streamAttr) < 0) {
        LOGE("get_resolution failed\n");
    }
    
    NetCaptureSetConfig(streamAttr.height, streamAttr.width, streamAttr.framerate);

    ENUM_FRAMETYPE Frame_Type = FAC_FRAME_P;
    Frame_Type = stPackVideo.stDataType.enFrameType == MEDIA_VIDEO_FRAME_TYPE_I ? FAC_FRAME_I : FAC_FRAME_P;
    FacTool_SendVideo(stPackVideo.pFrameData, stPackVideo.frameSize, (time_t)(stPackVideo.timestamp/1000), Frame_Type);
#endif /* FACTOOL_PROTOCOL */

#ifdef ALEXA_PROTOCOL
    Alexa_SendVideo(stPackVideo.pFrameData, stPackVideo.frameSize);
#endif /* ALEXA_PROTOCOL */

    return 0;
}


static int OnAudioData(int chn, MEDIA_PACK_AUDIO stPackAudio)
{
#ifdef ZDK_PROTOCOL
    RealTimeSendAudioData(0, (void*)stPackAudio.pFrameData, stPackAudio.frameSize, 
                            (unsigned int)(stPackAudio.timestamp/1000));
#endif /* ZDK_PROTOCOL */

#ifdef YD_PROTOCOL
  	DOTAudioPushData((unsigned char *)stPackAudio.pFrameData+4, (unsigned int)stPackAudio.frameSize-4,
							(unsigned int)(stPackAudio.timestamp/1000));
	DOTHjghPutAudioDateToList((unsigned char *)stPackAudio.pFrameData+4, stPackAudio.frameSize-4);

#endif /* YD_PROTOCOL */

#ifdef FACTOOL_PROTOCOL  //need g711 but audio is aac
#ifdef ZDK_PROTOCOL
    FacTool_SendAudio(stPackAudio.pFrameData, stPackAudio.frameSize);
#else
    FacTool_SendAudio(stPackAudio.pFrameData+4, stPackAudio.frameSize-4); /* hisi g711a, offset 4bytes */
#endif /* ZDK_PROTOCOL */
#endif /* FACTOOL_PROTOCOL */

#if 0
#ifdef ALEXA_PROTOCOL  /* need pcm not aac */
    Alexa_SendAudio(stPackAudio.pFrameData, stPackAudio.frameSize);
#endif /* ALEXA_PROTOCOL */
#endif

    return 0;
}

int ProtocolInit(void)
{
#ifdef MINI_APP
    UpgradeRecoveryStart(UPGRADE_STATUS_SHUTDOWN_FAIL);
    return 0;
#endif /* MINI_APP */

    int ret = 0;
    pthread_t protInitPid;
    pthread_t procCheckPid;	

#ifdef YD_PROTOCOL
	DOTMediaInit();
#endif /* YD_PROTOCOL */

	/* door bell key event register */
	ret = KeyEventRegister(KEY_TYPE_BELL, KEY_STATE_PRESSED, OnDoorBellEvent);
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, AV_FAILURE, "KeyEventRegister doorbell");

	/* pickalarm key event register */
	ret = KeyEventRegister(KEY_TYPE_PICK, KEY_STATE_PRESSED, OnPickAlarmEvent);
	AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, AV_FAILURE, "KeyEventRegister pickalarm");
	
	/* factory recovery key event register */

    if (PRODUCT_MODEL_B5 == ProductGetHandle()->ProductModel) {
        ret = KeyEventRegister(KEY_TYPE_CONFIG, KEY_STATE_LONGRESS, system_enter_ultra_deepsleep_cb);
        AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, AV_FAILURE, "KeyEventRegister system_enter_ultra_deepsleep_cb");
    } else {
        ret = KeyEventRegister(KEY_TYPE_CONFIG, KEY_STATE_LONGRESS, restore_factory_default_cb);
        AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, AV_FAILURE, "KeyEventRegister restore_factory_default_cb");
    }
	
    /* video and audio data recv register */
    VideoRegisterRecvData(0, OnVideoData);
    AudioRegisterRecvData(0, OnAudioData);

    /* protocol init thread, because the fun is blocked */
    ret = pthread_create(&protInitPid, NULL, &tskProtocolInit, NULL);
	AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, AV_FAILURE, "pthread_create tskProtocolInit");

	/* check status*/
    ret = pthread_create(&procCheckPid, NULL, &tskCheckStatus, NULL);
	AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, AV_FAILURE, "pthread_create tskCheckStatus");

	return 0;
}

int ProtocalSleepFreeResource()
{
#ifdef ALEXA_PROTOCOL
	Alexa_Stop();
#endif
	return 0;
}

